﻿using System;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.Threading;
using System.Management;
using System.Net;
using System.ServiceProcess;
using System.Windows.Forms;
using System.IO;
using System.Text.RegularExpressions;

using RealTimePriceFetchService.BLL;
using RealTimePriceFetchService.Model;

using LanceZhang.StockLib;

namespace LanceZhang.RealTimePriceFetchService
{
    public class Program : ServiceBase
    {
        private static int WorkThreads = Convert.ToInt32(ConfigurationManager.AppSettings["WorkThreads"]);
        private static int SleepTime = Convert.ToInt32(ConfigurationManager.AppSettings["SleepTime"]);
        private static int CheckTime = Convert.ToInt32(ConfigurationManager.AppSettings["CheckTime"]);
        private static bool LogToFile = ConfigurationManager.AppSettings["LogToFile"] == "1" ? true : false;
        private static bool EnableZip = ConfigurationManager.AppSettings["EnableZip"] == "1" ? true : false;
        private static string ServiceRealName = ConfigurationManager.AppSettings["ServiceName"];
        private static string ServiceDisPlayName = ConfigurationManager.AppSettings["ServiceDisPlayName"];
        private static string ServiceDescription = ConfigurationManager.AppSettings["ServiceDescription"];

        private static object lockobj = new object();

        private static string IP = GetIPAddress();
        private static string MAC = GetMacAddress();

        private static string prefixsh = "sh";
        private static string prefixsz = "sz";
        private static string endfix = ",";

        //服务所在路径
        private static string ServicePath = Application.ExecutablePath;
        private static string ServiceDirectory = Path.GetDirectoryName(ServicePath);

        //单线程
        private static Thread t;
        //多线程
        private static Thread[] threads;

        //公共StringBuilder
        private static StringBuilder sb = new StringBuilder();

        //股票查询字符串列表
        private static List<string> querylist=new List<string>();

        //调试模式开关
        private static int Debug = 0;

        //服务是否停止开关
        private static bool Stopped = false;

        private static bool CanStopped = false;

        //线程状态字典
        private static Dictionary<string, bool> DicStatus = new Dictionary<string, bool>();

        //状态线程
        private static Thread threadStatus;

        //业务逻辑对象
        private static SHAStockCodeBLL bllcode=new SHAStockCodeBLL();
        private static StockTransferQueueBLL bllqueue = new StockTransferQueueBLL();

        //时间标记
        private static DateTime t930;
        private static DateTime t1130;
        private static DateTime t1300;
        private static DateTime t1500;


        #region 应用程序初始化
        private static void InitilizeCompoment()
        {
            Output("开始初始化", true);
            if (Debug == 1)
            {
                Console.Title = ServiceDisPlayName;
            }

            if (WorkThreads < 1)
            {
                WorkThreads = 1;
            }

            Output("IP：" + IP, ConsoleColor.Green,true);
            Output("MAC：" + MAC, ConsoleColor.Green, true);
            Output("开始获取数据", ConsoleColor.Green, true);

            //构造查询字符串
            BuildQueryList();

            //初始化定时器
            //InitilizeTimer();

            //开启状态线程
            threadStatus = new Thread(TimeStatus);
            threadStatus.Start();


            //开始启动线程
            if (WorkThreads == 1)
            {
                t = new Thread(GetPrice);
                t.IsBackground = false;
                t.Start();
            }
            else
            {
                threads = new Thread[WorkThreads];

                DicStatus.Clear();

                for (int i = 0; i < WorkThreads; i++)
                {
                    DicStatus.Add("Threads" + (i + 1).ToString(), false);

                    threads[i] = new Thread(new ParameterizedThreadStart(GetPriceMulti));
                    threads[i].IsBackground = false;
                    threads[i].Name = "Threads" + (i + 1).ToString();
                    threads[i].Start(i);
                    Output("线程启动："+i.ToString(),ConsoleColor.Yellow, true);
                }
            }

            if (Debug == 1)
            {
                Console.ReadLine();
                Output("启动完成", true);
            }
        }

        //构造查询字符串
        private static void BuildQueryList()
        {
            Output("正在构造查询字符串...",ConsoleColor.Magenta, true);

            List<SHAStockCodeModel> all = (bllcode.GetModelList(""));

            Output("数据已读取条数：" + all.Count.ToString(),ConsoleColor.Magenta, true);

            //构造每线程工作量
            int batchcount = Convert.ToInt32(Math.Ceiling(Convert.ToDecimal(all.Count)/Convert.ToDecimal(WorkThreads)));

            Output(batchcount.ToString(), true);//debug

            for (int i = 0; i < WorkThreads; i++)
            {
                for (int j = 1; j < batchcount+1; j++)
                {
                    int index = i * batchcount + j;

                    if (index > all.Count-1)
                    {
                        break;
                    }

                    //new add for sz
                    if (all[index-1].StockCode < 599999)
                    {
                        sb.Append(prefixsz);
                    }
                    else
                    {
                        sb.Append(prefixsh);
                    }
                    sb.Append(all[index-1].StockCode.ToString("000000"));
                    sb.Append(endfix);
                }

                if (i == (WorkThreads - 1))//最后一轮循环特例，否则会遗漏最后一个元素
                {
                    if (all[all.Count - 1].StockCode < 599999)
                    {
                        sb.Append(prefixsz);
                    }
                    else
                    {
                        sb.Append(prefixsh);
                    }
                    sb.Append(all[all.Count - 1].StockCode.ToString("000000"));
                    sb.Append(endfix);
                }

                querylist.Add(sb.ToString());

                Output(sb.ToString(), true);//debug

                sb.Remove(0, sb.Length);
            }

            Output("查询字符串构造完成", ConsoleColor.Magenta, true);
        }

        #endregion

        #region 数据获取逻辑

        private static void GetPrice()
        {

        }

        private static void GetPriceMulti(object o)
        {
            int mod = (int)o;

            string threadname = "Threads" + (mod + 1).ToString();

            string result = string.Empty;
            string zipresult = string.Empty;
            StockTransferQueueModel model = new StockTransferQueueModel();

            while (true)
            {
                if (Stopped)
                {
                    lock (lockobj)
                    {
                        DicStatus[threadname] = true;
                    }

                    break;
                }

                try
                {
                    result = GetJSbyWC(querylist[mod]);
                }
                catch(Exception x)
                {
                    Output("从网络获取数据时发送错误：" + x.Message,ConsoleColor.Red, true);
                    Thread.Sleep(SleepTime/2);
                    continue;
                }


                if (EnableZip)
                {
                    zipresult = Compress.ZipString(result);
                    model.RealTimePrice = zipresult;
                }
                else
                {
                    model.RealTimePrice = result;
                }

                try
                {
                    bllqueue.Add(model);
                    Output("线程 " + mod.ToString() + " 添加记录成功", ConsoleColor.Blue, true);
                }
                catch (Exception e)
                {
                    Output("存储记录时产生错误： " + e.Message, ConsoleColor.Red, true);
                }

                Thread.Sleep(SleepTime);

                continue;
            }
        }

        #region 获取新浪清单，每秒4.5个，二方法耗时基本相等

        private static string GetJSbyWC(string code)
        {
            using (WebClient wc = new WebClient())
            {
                Stream resStream = wc.OpenRead("http://hq.sinajs.cn/list=" + code);
                StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default);
                string result = sr.ReadToEnd();
                resStream.Close();
                return result;
            }
        }

        private static string GetJSbyHTTP(string code)
        {

            WebRequest request = WebRequest.Create("http://hq.sinajs.cn/list=" + code);
            WebResponse response = request.GetResponse();
            Stream resStream = response.GetResponseStream();
            StreamReader sr = new StreamReader(resStream, System.Text.Encoding.Default);
            string result = sr.ReadToEnd();
            resStream.Close();
            sr.Close();

            return result;
        }

        #endregion

        #endregion

        #region 应用程序入口
        static void Main(string[] args)
        {
            Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Program_UnhandledException);
            Application.ThreadException += new ThreadExceptionEventHandler(Application_ThreadException);

            bool exists = ServiceControl.CheckService(ServiceRealName);

            if (args.Length == 0)
            {
                ServiceBase.Run(new ServiceBase[] { new Program() });
            }
            else
            {
                string parm = args[0].ToLower();

                switch (parm)
                {
                    case "-debug":
                    case "/debug":

                        Debug = 1;

                        if (exists)
                        {
                            ServiceControllerStatus status = ServiceControl.GetServiceStatus(ServiceRealName);

                            if (status != ServiceControllerStatus.Stopped)
                            {
                                Console.WriteLine(GetDateTime() + ServiceRealName + " 服务正在运行，无法进入调试状态。请先停止该服务");
                                Console.WriteLine(GetDateTime() + "请关闭本窗体");
                                Console.ReadLine();
                            }
                            else
                            {
                                InitilizeCompoment();
                            }
                        }
                        else
                        {
                            InitilizeCompoment();
                        }


                        break;

                    case "-install":
                    case "-setup":
                    case "/install":
                    case "/setup":

                        if (exists)
                        {
                            Console.WriteLine(GetDateTime() + ServiceRealName + " 服务已经存在，如果您想升级服务，请先卸载该服务");
                            Console.WriteLine(GetDateTime() + "请关闭本窗体");
                            Console.ReadLine();
                        }
                        else
                        {
                            Console.WriteLine(GetDateTime() + ServicePath);

                            bool result = ServiceControl.InstallService(ServicePath, ServiceRealName, ServiceDisPlayName, ServiceDescription);

                            if (result)
                            {
                                Console.WriteLine(GetDateTime() + "服务安装成功");
                                Console.WriteLine(GetDateTime() + "正在启动服务...");

                                ServiceControl.StartService(ServiceRealName);

                                while (!(ServiceControl.GetServiceStatus(ServiceRealName) == ServiceControllerStatus.Running))
                                {
                                    Thread.Sleep(SleepTime);
                                }

                                Console.WriteLine(GetDateTime() + "服务已经启动");
                            }
                            else
                            {
                                Console.WriteLine(GetDateTime() + "服务安装失败");
                            }

                            Console.WriteLine(GetDateTime() + "请关闭本窗体");
                            Console.ReadLine();
                        }
                        break;

                    case "-uninstall":
                    case "-remove":
                    case "/uninstall":
                    case "/remove":

                        if (!exists)
                        {
                            Console.WriteLine(GetDateTime() + ServiceRealName + " 服务尚未安装");
                        }
                        else
                        {
                            bool result = ServiceControl.UnInstallService(ServiceRealName);

                            if (!result)
                            {
                                Console.WriteLine(GetDateTime() + "服务卸载失败");
                            }
                            else
                            {
                                Console.WriteLine(GetDateTime() + "服务卸载成功");
                            }
                        }

                        Console.WriteLine(GetDateTime() + "请关闭本窗体");
                        Console.ReadLine();

                        break;

                }

            }
        }

        static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            Output("未处理A：" + e.Exception.Message, ConsoleColor.Red, true);
        }

        static void Program_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            if (e.ExceptionObject is System.Exception)
            {
                Output("未处理P：" + ((System.Exception)e.ExceptionObject).Message, ConsoleColor.Red, true);
            }

        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {

            }

            base.Dispose(disposing);
        }

        public Program()
        {
            base.ServiceName = ServiceRealName;
            base.AutoLog = true;
        }

        #endregion

        #region 初始化服务设置
        protected override void OnStart(string[] args)
        {
            InitilizeCompoment();
        }

        protected override void OnStop()
        {

            Stopped = true;

            try
            {
                if (WorkThreads == 1)
                {
                    while (!CanStopped)
                    {
                        Thread.Sleep(SleepTime);
                    }
                }
                else
                {
                    while (!AllStop())
                    {
                        Thread.Sleep(SleepTime);
                    }
                }
            }
            catch
            {
            }

        }

        /// <summary>
        /// 判断工作线程是否已经都停止了
        /// </summary>
        /// <returns></returns>
        private static bool AllStop()
        {
            try
            {
                lock (lockobj)
                {
                    foreach (bool value in DicStatus.Values)
                    {
                        if (!value)
                        {
                            return false;
                        }
                    }
                }

                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region 辅助逻辑

        #region 调试

        private static string GetDateTime()
        {
            return "[" + DateTime.Now.ToString("HH:mm:ss") + "] ";
        }

        private static void Output(string msg)
        {
            lock (lockobj)
            {
                if (Debug == 1)
                {
                    Console.WriteLine(GetDateTime() + msg);
                }
            }
        }

        private static void Output(string msg, bool log)
        {
            lock (lockobj)
            {
                if (Debug == 1)
                {
                    Console.WriteLine(GetDateTime() + msg);
                }

                if (log)
                {
                    if (LogToFile)
                    {
                        Log.WriteToFile(ServiceDirectory + @"\log_" + DateTime.Now.ToString("yyyyMMdd") + ".txt", GetDateTime() + msg);
                    }
                }
            }
        }

        private static void Output(string msg, ConsoleColor color)
        {
            lock (lockobj)
            {
                if (Debug == 1)
                {
                    Console.ForegroundColor = color;
                    Console.WriteLine(GetDateTime() + msg);
                    Console.ResetColor();
                }
            }
        }

        private static void Output(string msg, ConsoleColor color, bool log)
        {
            lock (lockobj)
            {
                if (Debug == 1)
                {
                    Console.ForegroundColor = color;
                    Console.WriteLine(GetDateTime() + msg);
                    Console.ResetColor();
                }

                if (log)
                {
                    if (LogToFile)
                    {
                        Log.WriteToFile(ServiceDirectory + @"\log_" + DateTime.Now.ToString("yyyyMMdd") + ".txt", GetDateTime() + msg);
                    }
                }
            }
        }

        #endregion

        #region 获得IP地址
        private static string GetIPAddress()
        {

            IPAddress[] ips = Dns.GetHostAddresses(Dns.GetHostName());

            string ip = string.Empty;

            for (int i = 0; i < ips.Length; i++)
            {
                ip += ips[i].ToString() + ",";
            }

            if (ip != string.Empty)
            {
                ip = ip.Substring(0, ip.Length - 1);
            }

            return ip;

            /*
            string ip = string.Empty;
            ManagementClass mc = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection moc = mc.GetInstances();

            foreach (ManagementObject mo in moc)
            {
                if ((bool)mo["IPEnabled"] == true)
                {
                    string[] ipaddresses = (string[])mo["IPAddress"];

                    for (int i = 0; i < ipaddresses.Length; i++)
                    {
                        ip += ipaddresses[i].ToString() + ",";
                    }
                }
            }

            if (ip != string.Empty)
            {
                ip = ip.Substring(0, ip.Length - 1);
            }

            return ip;
           */

        }
        #endregion

        #region 获得MAC
        private static string GetMacAddress()
        {
            ManagementClass adapters = new ManagementClass("Win32_NetworkAdapterConfiguration");
            string MACAddress = string.Empty;
            foreach (ManagementObject adapter in adapters.GetInstances())
            {
                if ((bool)adapter["IPEnabled"] == true)
                {
                    MACAddress = adapter.Properties["MACAddress"].Value.ToString();
                    MACAddress += ",";
                }
            }

            //去除最后一个,号
            if (MACAddress != string.Empty)
            {
                MACAddress = MACAddress.Substring(0, MACAddress.Length - 1);
            }

            return MACAddress;
        }
        #endregion

        #endregion

        #region 时间状态控制

        /// <summary>
        /// 接收状态
        /// </summary>
        private static void TimeStatus()
        {

            while (true)
            {
                if (isTodayHoliday() || isFreeTime())
                {
                    Output("目前非交易时间",ConsoleColor.Green, true);
                    Stopped = true;
                }
                else
                {
                    if (Stopped)
                    {
                        Output("目前是交易时间", ConsoleColor.Green, true);
                        Stopped = false;
                        InitilizeCompoment();
                    }
                }

                Thread.Sleep(CheckTime);
            }
        }

        /// <summary>
        /// 当天是否周末休市
        /// </summary>
        /// <returns></returns>
        private static bool isTodayHoliday()
        {
            if (DateTime.Now.DayOfWeek == DayOfWeek.Saturday || DateTime.Now.DayOfWeek == DayOfWeek.Sunday)
            {
                return true;
            }
            return false;
        }

        /// <summary>
        /// 当时间是否是非交易时间
        /// </summary>
        /// <returns></returns>
        private static bool isFreeTime()
        {

            t930 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 9, 30, 0);
            t1130 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 11, 36, 0);
            t1300 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 13, 0, 0);
            t1500 = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, 15, 6, 0);

            if ((DateTime.Now > t930) && (DateTime.Now < t1130) || (DateTime.Now > t1300) && (DateTime.Now < t1500))
            {
                return false;
            }
            else
            {
                return true;
            }
        }


        #endregion
    }
}
